Sys.setenv(LANG = "en")
library(pROC)
Type 'citation("pROC")' for a citation.
Attaching package: ‘pROC’
The following objects are masked from ‘package:stats’:
cov, smooth, var
setwd("C:/Users/halan/Desktop/FPU/SPring2025/StatisticalLearning")
incidents <- read.csv("mass_killing_incidents_public.csv")
offenders <- read.csv("mass_killing_offenders_public.csv")
victims <- read.csv("mass_killing_victims_public.csv")
weapons <- read.csv("mass_killing_weapons_public.csv")
view(incidents)
view(offenders)
view(victims)
view(weapons)
DATA: Mass Killing Database 2006 - Present (AS OF MARCH 15th
2025)
Mass Murder for this dataset is defined as “…the intentional killing
of four or more victims by any means within a 24-hour period, excluding
the death of unborn children and the offender(s).)
This Database is constantly being updated (Was just updated 2 hours
ago as of March 16th, 2025 at 12:50PM) and I would say is very
trustworthy. The contact details for this Database is Justin Myers.
Justin Myers is a veteran journalist for “The Associated Press”, they
are also working with Northeastern University’s James Alan Fox whom is
also a contact.
Features(Incident [19 Columns x 615 Rows]):
Red = Categorical | Green = Numerical
- incident_id: ID of incident
- date: Date of incident
- city: City/Town name
- state: State postal code
- num_offenders: Number of
offenders
- num_killed: Number of victims
killed
- num_injured: Numnber of victims
injured
- firstcod: First cause of death
- secondcod: Second cause of death
- if_assault_rifle: Whether a rifle was
used
- type: Type of incident (ie. Family,
Felony, Public, etc.)
- situation_type: Type of situation
(ie. Arson, Drug Trade, Family Issue, etc.)
- location_type: Type of location (ie.
Commercial/Retail/Entertainment, Government/Transit, House of worship,
etc.)
- location: Location (ie.
Bar/Club/Restaurant, College, Commercial/Retail, etc.)
- longitude
- latitude
- county: County associated with
coordinates
- geocode: FIPS geocode of
location
- narrative: Description of incident
Features(Victims [6 Columns x 3174 Rows]):
- incident_id: ID for incident, used to
link the victims data.
- victim_id: ID of the victim, for
recording purposes.
- age: Age of the victim.
- race
- sex
- vorelationship: Relationship of
victim to the offender
Features(Weapons [5 Columns x 963 Rows]):
- incident_id: ID for incident, used to
link weapon to incident.
- weapon_id: ID for weapon
identification.
- weapon_type: Type of weapon.
- gun_class: Classification of gun
(Handgun, Long gun, Unknown gun class, Non-gun)
- gun_type: Type of gun (ie. Handgun,
Pistol, Revolver, Rifle, etc.)
Features(Offenders [15 Columns x 788 Rows]):
- incident_id: ID of incident, used to
connect the 4 data sets.
- offender_id: ID used for
classification of offenders (Mostly for multi-offender incidents)
- firstname
- middlename
- lastname
- suffix
- age
- race
- sex
- suicide: Whether the offender
commited suicide or not.
- deathcause: What did the offender die
by whether it was suicide or killed by a bystander/police
- outcome: What was the legal outcome
for the incident (ie. Acquitted, Arrested/Pending trial, Charges
dropped, etc.)
- criminal_justice_process: Status of
criminal justice process (ie. Arrested/Pending trial, charges dropped,
etc.)
- sentence_type: Type of sentence
convicted (ie. Acquitted, Awaiting sentencing, Committed, Death sentence
etc.)
- sentence_details: Details about the sentence convicted.
glimpse(incidents)
Rows: 615
Columns: 19
$ incident_id <int> 644, 643, 642, 639, 641, 638, 637, 636, 635, 634, 632, 631, 629, 630, 627, 626, 625, 624, 623, 620, 619, 618, 616, 615, 614, 613…
$ date <chr> "2025-02-21", "2025-02-10", "2025-01-01", "2024-12-14", "2024-12-14", "2024-12-07", "2024-11-16", "2024-11-10", "2024-11-07", "2…
$ city <chr> "Lake Station", "Byron", "New Orleans", "Belen", "West Valley", "DeKalb County", "Lancaster", "Wichita", "Duluth", "Fall City", …
$ state <chr> "IN", "WY", "LA", "NM", "UT", "GA", "CA", "KS", "MN", "WA", "AL", "GA", "IL", "NY", "NY", "GA", "FL", "NY", "AL", "AL", "CA", "K…
$ num_offenders <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 5, 1, 1, 1, 3, 1, 1,…
$ num_victims_killed <int> 4, 4, 14, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 5, 6, 4, 8, 4, 4, 6, 4…
$ num_victims_injured <int> 0, 0, 30, 0, 1, 0, 0, 0, 0, 1, 17, 9, 0, 0, 0, 0, 0, 0, 0, 10, 0, 3, 1, 9, 0, 0, 4, 0, 7, 0, 0, 7, 0, 0, 1, 2, 0, 0, 1, 0, 0, 3,…
$ firstcod <chr> "Shooting", "Shooting", "Vehicle crash", "Shooting", "Shooting", "Shooting", "Shooting", "Shooting", "Shooting", "Shooting", "Sh…
$ secondcod <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "Smoke inhalation & burns", "", "", "", "Stabbing", "", "", "", "", "", "", …
$ if_assault_rifle_used <chr> "Unknown gun type", "Gun not an assault rifle", "Nongun", "Gun not an assault rifle", "Unknown gun type", "Unknown gun type", "G…
$ type <chr> "Family", "Family", "Public", "Family", "Family", "Family", "Undetermined", "Family", "Family", "Family", "Suspected felony", "P…
$ situation_type <chr> "Family issue", "Despondency", "Terrorism", "", "", "Family issue", "", "", "", "Family issue", "Other", "Indiscriminate", "Unde…
$ location_type <chr> "Residence/Other shelter", "Residence/Other shelter", "Open space", "Residence/Other shelter", "Residence/Other shelter", "Resid…
$ location <chr> "Residence", "Residence", "Open space", "Residence", "Residence", "Residence", "Residence", "Residence", "Residence", "Residence…
$ longitude <dbl> -87.25547, -108.50082, -90.06991, -106.68182, -111.97256, -84.31904, -118.11650, -97.32347, -92.15961, -121.88448, -86.79633, -8…
$ latitude <dbl> 41.59381, 44.79471, 29.95388, 34.56935, 40.69044, 33.72203, 34.69170, 37.65839, 46.74984, 47.53114, 33.50061, 33.94773, 41.87422…
$ county <chr> "Lake County", "Big Horn County", "Orleans Parish", "Valencia County", "Salt Lake County", "DeKalb County", "Los Angeles County"…
$ census_tract_geoid <dbl> 18089041700, 56003962800, 22071013400, 35061971100, 49035113309, 13089023702, 6037900607, 20173003900, 27137015800, 53033032605,…
$ narrative <chr> "While conducting a welfare check at a Lake Station, IN, home, the police discovered the bodies of a man, a woman, a three child…
Filling in blank information for clarity.
unique(incidents$situation_type)
[1] "Family issue" "Despondency" "Terrorism" "" "Other" "Indiscriminate"
[7] "Undetermined" "Robbery" "Arson" "Interpersonal conflict" "Gang conflict" "Drug trade"
[13] "Employment grievance" "Hate" "Profit"
incidents$situation_type[incidents$situation_type == ""] <- "Unknown"
unique(incidents$situation_type)
[1] "Family issue" "Despondency" "Terrorism" "Unknown" "Other" "Indiscriminate"
[7] "Undetermined" "Robbery" "Arson" "Interpersonal conflict" "Gang conflict" "Drug trade"
[13] "Employment grievance" "Hate" "Profit"
Here is a quick diagram of the US (Excluding Alaska and Hawaii as
it’s not properly fitted) that showcases where all the incidents took
place. The plan is for me to eventually also turn this into a heat map
to give a better gauge as when there are multiple like this it is
difficult to showcase how much there is due to overlap. I am also
attempting two different ways of showing the data points. Eventually
I’ll figure out which would be the most effective method.
varI <- incidents %>%
select(c(incident_id, longitude, latitude, firstcod, situation_type, location, num_victims_killed, num_victims_injured)) %>%
rename(lon = longitude) %>%
rename(lat = latitude)
varI
transformedData <- usmap_transform(varI)
tempData <- transformedData %>%
filter(row_number() != 262)

# Excluding the 2017 Las Vegas Nevada shooter incident as it gets in the way of clarity.
tempData <- transformedData %>%
filter(row_number() != 262)
plot_usmap() + geom_sf(
data = tempData,
aes(color = firstcod, size = num_victims_injured),
alpha = .5) +
theme(legend.position = "right", legend.key.size = unit(1, 'mm'), plot.title=element_text(hjust=0.5, face = "bold")) +
labs(title = "PRIMARY reason for injured victims", caption = "-The 2017 Las Vegas Shooter has been excluded for clarity. That event had 60 deaths and 867 injured.")





# Getting a count of the incidents per state
stateIncidents <- incidents %>%
count(state)
# Setting a fill color variable dependent on the number of incidents
stateIncidents <- stateIncidents %>%
mutate(fillColor = ifelse(n>=40, "40+", ifelse(n>=20, "20-39", "0-19")))
Here is a bar graph statistic showcasing all of the incidents from
the data set and showing them from most to least in a bar graph form.
From this we can see that California, Texas and Illinois are the three
most dangerous (in the sense of the most mass murders occuring)
locations in the US. Florida being an honorable mention for fourth
place. From here on I could also then further test to check the amount
of victims, whilst this graph shows the most mass killings in occurrence
for the past ~20 years, that does not necessarily pertain to deadliness
as there may be other states that have less but more severe mass
murders.

# Getting a sum of the amount of both victims killed and injured per state
deadlynessPerState <- incidents %>%
group_by(state) %>%
summarize(totalDeaths = sum(num_victims_killed), totalInjured = sum(num_victims_injured))
# Now applying a manual fill variable to be able to apply to the graph later
deadlynessPerState <- deadlynessPerState %>%
mutate(fillColorDeath = ifelse(totalDeaths>=200, "200+", ifelse(totalDeaths>=100, "100-199", "0-99")),
fillColorInjury = ifelse(totalInjured>=200, "200+", ifelse(totalDeaths>=100, "100-199", "0-99")))


ggplot(weapons, aes(x = weapon_type)) +
geom_bar(width = 0.8)

With this Violin plot (+ Boxplot) we can see the general distribution
of the victims as well as the medians. Generally it seems that females
and males are both on average not too dissimilar but this is without
knowing the exact amount of numbers. Proportionally however, the age of
which they died does not seem to matter despite the sex. The unknown
seems to be cases which the bodies were recovered but maybe not able to
be identified as these cases have little to no information to them

I specifically remember this occurrence, I recall it being everywhere
on the news and so I tested out the ID and seeing how well I could
extract the data.
incidentsFL <- incidents %>%
filter(state == "FL")
incidentsFL
weapons %>%
filter(incident_id == 300)
victims %>%
filter(incident_id == 300)
offenders %>%
filter(incident_id == 300)
Here I was checking if there are any other discriminatory attacks
against gay people searching through the narratives for the term “gay”,
surprisingly, out of all the ones in the US only one showed up, which is
the same one from above that occurred in Orlando.
# With grepl I can search for specific words in the narrative or any other of the strings of texts that give narratives.
incidents %>%
filter(grepl("gay", narrative))
NA
I would consider this data set to be relatively clean. But,
there are some things that could be altered for the sake of working with
them. For example, there are a lot of NULL cells but due to the type of
data I do not plan to remove these rows, I will however probably change
them into “N/A” or something of the sort as they are important. There
are some features, for example - situation_type, which has
“Undetermines” and just flat out Null. Reading through the narratives,
my personal belief is that these are most likely incidents in which
there was simply no official statement of what type of situation the
incident was. This would be a situation in which I would alter the data
to officially state something like “Not Stated”
Discussion:
My general impression on this data set is that while it is very
interested, at least for me, it does pose the challenge of attempting to
do any sort of predictions. A lot of this data is simply fact but
because of the nature of the data I cannot seem to do any sort of time
series data as the dates could be considered as continuous but the
situations are separate and not linked together.
Regarding the type of models, I’m thinking of maybe using a type of
linear regression model to see if maybe there is any correlation with
certain features to determine/predetermine the potential lethality of a
situation based on the information it has given us. This would be tricky
as things like race and age are too broad and other features like
situation_type are generally hard to gague before the situation has
already escalated. That said I’ll attempt to at least see what I would
be able to predict like maybe what the odds are of survival with
specific body types (age, sex, race, etc.) have in their respective
situations. This could be done with the usage of linear regression.
fullMergedClean <- subset(fullMerged, select = -c(incident_id, location_type, longitude, latitude, census_tract_geoid, narrative, firstname, lastname, middlename, suffix, deathcause, outcome, criminal_justice_process, sentence_type, sentence_details, victim_id, weapon_id, ))
Error in c(incident_id, location_type, longitude, latitude, census_tract_geoid, :
argument 18 is empty
fullMergedClean$had_survivor <- ifelse(fullMergedClean$num_victims_injured > 0, "Yes", "No")
fullMergedClean$had_survivor <- as.factor(fullMergedClean$had_survivor)
non_numeric_cols
[1] "weekday" "state" "firstcod" "secondcod" "if_assault_rifle_used" "situation_type"
[7] "location" "race.x" "sex.x" "race.y" "sex.y" "vorelationship"
[13] "weapon_type" "gun_class" "gun_type" "had_survivor"
incidents
offenders
victims
weapons
FEATURE ENGINEER, GOING TO MERGE EVERYTHING Features wanted
incident_id, date, state, num_offenders, num_victims_killed,
num_victims_injured, firstcod, if_assault_rifle_used, situation_type,
location, offender_age, offender_race, offender_sex, victim_age,
victim_sex, vorelationship, weapon_type
ADD num_victims_total
Turn Categorical into dummy variables
# Fixing the date and adding extra date columns.
incidentsUpdated <- incidents %>%
mutate(
date = as.Date(date),
year = year(date),
month = month(date),
day = day(date),
weekday = weekdays(date)
)
incidentsUpdated <- na.omit(incidentsUpdated)
incidentsUpdated$had_survivor <- ifelse(incidentsUpdated$num_victims_injured > 0, "Yes", "No")
incidentsUpdated$had_survivor <- as.factor(incidentsUpdated$had_survivor)
# [Name] Summaries, these will get all the columns that will be used for the models.
incidentsSum <- incidentsUpdated %>%
subset(select = c(incident_id, date, year, month, day, weekday, state, num_offenders, num_victims_killed, num_victims_injured, firstcod, situation_type, location, had_survivor))
offenderSum <- offenders %>%
subset(select = c(incident_id, offender_id, age, race, sex)) %>%
rename(offenderAge = age) %>%
rename(offenderRace = race) %>%
rename(offenderSex = sex)
victimSum <- victims %>%
subset(select = c(incident_id, victim_id, age, race, sex, vorelationship)) %>%
rename(victimAge = age) %>%
rename(victimRace = race) %>%
rename(victimSex = sex)
weaponSum <- weapons %>%
subset(select = c(incident_id, weapon_id, weapon_type))
# Merging the data
totalData <- incidentsSum %>%
left_join(offenderSum, by = "incident_id") %>%
left_join(victimSum, by = "incident_id") %>%
left_join(weaponSum, by = "incident_id")
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
totalData <- na.omit(totalData)
totalData
charEncode <- c("weekday", "state", "firstcod", "situation_type", "location", "offenderRace", "offenderSex", "victimRace", "victimSex", "vorelationship", "weapon_type")
# Turns any blank cells to "Unknown"
totalData[totalData == ""] <- "Unknown"
#any(is.na(totalData))
# This will factorize all of the data instead of having to manually do it
totalDataFactored <- totalData %>%
mutate(across(all_of(charEncode), ~ as.integer(factor(.x))))
# Sums the max value in all of the columns which should, in theory, give the total amount of distinct columns I should have.
sum(sapply(totalDataFactored[charEncode], max))
[1] 152
# Get all of the names and which column they were from
factorLookup <- totalData %>%
dplyr::select(charEncode) %>%
pivot_longer(cols = everything(),
names_to = "Origin",
values_to = "Name")
# Gathers all of the factored data
factorLookup2 <- totalDataFactored %>%
dplyr::select(charEncode) %>%
pivot_longer(cols = everything(),
names_to = NULL,
values_to = "Encoded Value")
# Assuming nothing has changed and having checked the number it matches up. I assume this is correct and now factorLookup is a good dictionary to go back to.
factorLookup <- cbind(factorLookup, factorLookup2)
factorLookup <- distinct(factorLookup)
factorLookup
splitData <- createDataPartition(binaryFactored$had_survivor, p = 0.8, list = FALSE)
trainData <- binaryFactored[splitData, ]
testData <- binaryFactored[-splitData, ]
# This is so that I can use it in the corr matrix but also make my life easier
totalDataFactoredForReal <- subset(totalDataFactored, select = -c(incident_id, date, year, month, offender_id, victim_id))
totalDataFactoredForReal$had_survivor <- as.numeric(totalDataFactoredForReal$had_survivor)
# Linear Regression Model
linModel <- lm(had_survivor ~ ., data = totalDataFactoredForReal)
summary(logModel)
Call:
lm(formula = had_survivor ~ ., data = totalDataFactoredForReal)
Residuals:
Min 1Q Median 3Q Max
-0.97413 -0.34860 -0.00111 0.30482 0.84998
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.705e+00 5.937e-02 28.724 < 2e-16 ***
day -4.216e-03 5.544e-04 -7.604 3.19e-14 ***
weekday 1.154e-02 2.514e-03 4.592 4.46e-06 ***
state -4.960e-04 3.283e-04 -1.511 0.13087
num_offenders -8.142e-03 3.775e-03 -2.157 0.03105 *
num_victims_killed 1.323e-02 7.730e-04 17.118 < 2e-16 ***
num_victims_injured -2.157e-04 5.540e-05 -3.893 9.97e-05 ***
firstcod 2.365e-02 5.646e-03 4.188 2.84e-05 ***
situation_type 1.169e-03 1.360e-03 0.859 0.39018
location -4.773e-02 1.499e-03 -31.844 < 2e-16 ***
offenderAge -2.790e-03 4.852e-04 -5.749 9.30e-09 ***
offenderRace 1.070e-03 2.895e-03 0.370 0.71176
offenderSex 1.233e-01 1.678e-02 7.350 2.17e-13 ***
victimAge 1.138e-03 2.484e-04 4.581 4.70e-06 ***
victimRace -2.621e-03 2.783e-03 -0.942 0.34631
victimSex -1.343e-02 8.880e-03 -1.513 0.13038
vorelationship -1.126e-04 5.381e-04 -0.209 0.83425
weapon_id -5.213e-05 1.702e-05 -3.062 0.00221 **
weapon_type -1.947e-02 4.101e-03 -4.748 2.09e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.3851 on 8108 degrees of freedom
Multiple R-squared: 0.3731, Adjusted R-squared: 0.3718
F-statistic: 268.1 on 18 and 8108 DF, p-value: < 2.2e-16
corM <- cor(totalDataFactoredForReal)
corrplot(corM, method = "color")

heatmap(corM, symm = TRUE, main = "Correlation Heatmap")

library(randomForest)
Warning: package ‘randomForest’ was built under R version 4.4.3randomForest 4.7-1.2
Type rfNews() to see new features/changes/bug fixes.
Attaching package: ‘randomForest’
The following object is masked from ‘package:dplyr’:
combine
The following object is masked from ‘package:ggplot2’:
margin
logModel <- glm(had_survivor~ . -num_victims_killed -num_victims_injured -had_survivor, data = trainData, family = "binomial")
stepLogModel <- step(logModel, direction = "both")
Start: AIC=6468.25
had_survivor ~ (day + weekday + state + num_offenders + num_victims_killed +
num_victims_injured + firstcod + situation_type + location +
offenderAge + offenderRace + offenderSex + victimAge + victimRace +
victimSex + vorelationship + weapon_id + weapon_type) - num_victims_killed -
num_victims_injured - had_survivor
Df Deviance AIC
- victimAge 1 6434.3 6466.3
<none> 6434.2 6468.2
- firstcod 1 6436.6 6468.6
- victimRace 1 6436.7 6468.7
- weekday 1 6437.3 6469.3
- state 1 6437.4 6469.4
- victimSex 1 6439.0 6471.0
- situation_type 1 6439.1 6471.1
- num_offenders 1 6442.7 6474.7
- weapon_id 1 6446.1 6478.1
- weapon_type 1 6450.8 6482.8
- offenderRace 1 6452.2 6484.2
- vorelationship 1 6463.9 6495.9
- offenderSex 1 6487.0 6519.0
- offenderAge 1 6489.8 6521.8
- day 1 6718.2 6750.2
- location 1 7431.4 7463.4
Step: AIC=6466.3
had_survivor ~ day + weekday + state + num_offenders + firstcod +
situation_type + location + offenderAge + offenderRace +
offenderSex + victimRace + victimSex + vorelationship + weapon_id +
weapon_type
Df Deviance AIC
<none> 6434.3 6466.3
- firstcod 1 6436.7 6466.7
- victimRace 1 6436.9 6466.9
- weekday 1 6437.3 6467.3
- state 1 6437.4 6467.4
+ victimAge 1 6434.2 6468.2
- victimSex 1 6439.0 6469.0
- situation_type 1 6439.2 6469.2
- num_offenders 1 6442.7 6472.7
- weapon_id 1 6446.4 6476.4
- weapon_type 1 6450.8 6480.8
- offenderRace 1 6452.4 6482.4
- vorelationship 1 6464.8 6494.8
- offenderSex 1 6487.2 6517.2
- offenderAge 1 6490.5 6520.5
- day 1 6719.1 6749.1
- location 1 7489.2 7519.2
stepLogModelCV <- train(had_survivor ~ . -num_victims_killed -num_victims_injured -had_survivor, data = trainData, method = "glm", family = "binomial", trControl = train_control, metric = "ROC")
stepLogPred <- predict(stepLogModelCV, newdata = testData, type = "prob")
rocOb <- roc(testData$had_survivor, stepLogPred$Yes)
Setting levels: control = Yes, case = No
Setting direction: controls > cases
plot(rocOb, print.auc = TRUE,
col = "blue",
lwd = 3,
legacy.axes = TRUE,
main = "ROC Curve for Survival Prediction")
abline(a = 0, b = 1, lty = 2, col = "red")

auc(rocOb)
Area under the curve: 0.8204
LS0tDQp0aXRsZTogIlByb2plY3Q6IE1hc3MgTXVyZGVyIFN0YXRpc3RpY3MiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmF1dGhvcjogIkhhbGFuIEJhZGlsbGEgT3NvcmlvIg0KLS0tDQoNCmBgYHtyfQ0KU3lzLnNldGVudihMQU5HID0gImVuIikNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShtYXBzKQ0KbGlicmFyeShtYXBwcm9qKQ0KbGlicmFyeSh1c21hcCkNCmxpYnJhcnkoSVNMUjIpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpsaWJyYXJ5KE1BU1MpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShoZXhiaW4pDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpsaWJyYXJ5KGNhcikNCmxpYnJhcnkocFJPQykNCmBgYA0KDQpgYGB7cn0NCnNldHdkKCJDOi9Vc2Vycy9oYWxhbi9EZXNrdG9wL0ZQVS9TUHJpbmcyMDI1L1N0YXRpc3RpY2FsTGVhcm5pbmciKQ0KDQppbmNpZGVudHMgPC0gcmVhZC5jc3YoIm1hc3Nfa2lsbGluZ19pbmNpZGVudHNfcHVibGljLmNzdiIpDQpvZmZlbmRlcnMgPC0gcmVhZC5jc3YoIm1hc3Nfa2lsbGluZ19vZmZlbmRlcnNfcHVibGljLmNzdiIpDQp2aWN0aW1zIDwtIHJlYWQuY3N2KCJtYXNzX2tpbGxpbmdfdmljdGltc19wdWJsaWMuY3N2IikNCndlYXBvbnMgPC0gcmVhZC5jc3YoIm1hc3Nfa2lsbGluZ193ZWFwb25zX3B1YmxpYy5jc3YiKQ0KYGBgDQoNCmBgYHtyfQ0KdmlldyhpbmNpZGVudHMpDQp2aWV3KG9mZmVuZGVycykNCnZpZXcodmljdGltcykNCnZpZXcod2VhcG9ucykNCmBgYA0KDQpEQVRBOiBNYXNzIEtpbGxpbmcgRGF0YWJhc2UgMjAwNiAtIFByZXNlbnQgKEFTIE9GIE1BUkNIIDE1dGggMjAyNSkNCg0KTWFzcyBNdXJkZXIgZm9yIHRoaXMgZGF0YXNldCBpcyBkZWZpbmVkIGFzICIuLi50aGUgaW50ZW50aW9uYWwga2lsbGluZyBvZiBmb3VyIG9yIG1vcmUgdmljdGltcyBieSBhbnkgbWVhbnMgd2l0aGluIGEgMjQtaG91ciBwZXJpb2QsIGV4Y2x1ZGluZyB0aGUgZGVhdGggb2YgdW5ib3JuIGNoaWxkcmVuIGFuZCB0aGUgb2ZmZW5kZXIocykuKQ0KDQpUaGlzIERhdGFiYXNlIGlzIGNvbnN0YW50bHkgYmVpbmcgdXBkYXRlZCAoV2FzIGp1c3QgdXBkYXRlZCAyIGhvdXJzIGFnbyBhcyBvZiBNYXJjaCAxNnRoLCAyMDI1IGF0IDEyOjUwUE0pIGFuZCBJIHdvdWxkIHNheSBpcyB2ZXJ5IHRydXN0d29ydGh5LiBUaGUgY29udGFjdCBkZXRhaWxzIGZvciB0aGlzIERhdGFiYXNlIGlzIEp1c3RpbiBNeWVycy4gSnVzdGluIE15ZXJzIGlzIGEgdmV0ZXJhbiBqb3VybmFsaXN0IGZvciAiVGhlIEFzc29jaWF0ZWQgUHJlc3MiLCB0aGV5IGFyZSBhbHNvIHdvcmtpbmcgd2l0aCBOb3J0aGVhc3Rlcm4gVW5pdmVyc2l0eSdzIEphbWVzIEFsYW4gRm94IHdob20gaXMgYWxzbyBhIGNvbnRhY3QuDQoNCg0KDQpGZWF0dXJlcyhJbmNpZGVudCBbMTkgQ29sdW1ucyB4IDYxNSBSb3dzXSk6DQoNCjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPlJlZDwvc3Bhbj4gPSBDYXRlZ29yaWNhbCB8IDxzcGFuIHN0eWxlPSJjb2xvcjpncmVlbiI+R3JlZW48L3NwYW4+ID0gTnVtZXJpY2FsDQoNCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+aW5jaWRlbnRfaWQ8L3NwYW4+OiBJRCBvZiBpbmNpZGVudA0KLSA8c3BhbiBzdHlsZT0iY29sb3I6Z3JlZW4iPmRhdGU8L3NwYW4+OiBEYXRlIG9mIGluY2lkZW50DQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPmNpdHk8L3NwYW4+OiBDaXR5L1Rvd24gbmFtZQ0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5zdGF0ZTwvc3Bhbj46IFN0YXRlIHBvc3RhbCBjb2RlDQotIDxzcGFuIHN0eWxlPSJjb2xvcjpncmVlbiI+bnVtX29mZmVuZGVyczwvc3Bhbj46IE51bWJlciBvZiBvZmZlbmRlcnMNCi0gPHNwYW4gc3R5bGU9ImNvbG9yOmdyZWVuIj5udW1fa2lsbGVkPC9zcGFuPjogTnVtYmVyIG9mIHZpY3RpbXMga2lsbGVkDQotIDxzcGFuIHN0eWxlPSJjb2xvcjpncmVlbiI+bnVtX2luanVyZWQ8L3NwYW4+OiBOdW1uYmVyIG9mIHZpY3RpbXMgaW5qdXJlZA0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5maXJzdGNvZDwvc3Bhbj46IEZpcnN0IGNhdXNlIG9mIGRlYXRoDQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPnNlY29uZGNvZDwvc3Bhbj46IFNlY29uZCBjYXVzZSBvZiBkZWF0aA0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5pZl9hc3NhdWx0X3JpZmxlPC9zcGFuPjogV2hldGhlciBhIHJpZmxlIHdhcyB1c2VkDQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPnR5cGU8L3NwYW4+OiBUeXBlIG9mIGluY2lkZW50IChpZS4gRmFtaWx5LCBGZWxvbnksIFB1YmxpYywgZXRjLikNCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+c2l0dWF0aW9uX3R5cGU8L3NwYW4+OiBUeXBlIG9mIHNpdHVhdGlvbiAoaWUuIEFyc29uLCBEcnVnIFRyYWRlLCBGYW1pbHkgSXNzdWUsIGV0Yy4pDQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPmxvY2F0aW9uX3R5cGU8L3NwYW4+OiBUeXBlIG9mIGxvY2F0aW9uIChpZS4gQ29tbWVyY2lhbC9SZXRhaWwvRW50ZXJ0YWlubWVudCwgR292ZXJubWVudC9UcmFuc2l0LCBIb3VzZSBvZiB3b3JzaGlwLCBldGMuKQ0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5sb2NhdGlvbjwvc3Bhbj46IExvY2F0aW9uIChpZS4gQmFyL0NsdWIvUmVzdGF1cmFudCwgQ29sbGVnZSwgQ29tbWVyY2lhbC9SZXRhaWwsIGV0Yy4pDQotIDxzcGFuIHN0eWxlPSJjb2xvcjpncmVlbiI+bG9uZ2l0dWRlPC9zcGFuPg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6Z3JlZW4iPmxhdGl0dWRlPC9zcGFuPg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5jb3VudHk8L3NwYW4+OiBDb3VudHkgYXNzb2NpYXRlZCB3aXRoIGNvb3JkaW5hdGVzDQotIDxzcGFuIHN0eWxlPSJjb2xvcjpncmVlbiI+Z2VvY29kZTwvc3Bhbj46IEZJUFMgZ2VvY29kZSBvZiBsb2NhdGlvbg0KLSBuYXJyYXRpdmU6IERlc2NyaXB0aW9uIG9mIGluY2lkZW50DQoNCg0KRmVhdHVyZXMoVmljdGltcyBbNiBDb2x1bW5zIHggMzE3NCBSb3dzXSk6DQoNCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+aW5jaWRlbnRfaWQ8L3NwYW4+OiBJRCBmb3IgaW5jaWRlbnQsIHVzZWQgdG8gbGluayB0aGUgdmljdGltcyBkYXRhLg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj52aWN0aW1faWQ8L3NwYW4+OiBJRCBvZiB0aGUgdmljdGltLCBmb3IgcmVjb3JkaW5nIHB1cnBvc2VzLg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6Z3JlZW4iPmFnZTwvc3Bhbj46IEFnZSBvZiB0aGUgdmljdGltLg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5yYWNlPC9zcGFuPg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5zZXg8L3NwYW4+DQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPnZvcmVsYXRpb25zaGlwPC9zcGFuPjogUmVsYXRpb25zaGlwIG9mIHZpY3RpbSB0byB0aGUgb2ZmZW5kZXINCg0KRmVhdHVyZXMoV2VhcG9ucyBbNSBDb2x1bW5zIHggOTYzIFJvd3NdKToNCg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5pbmNpZGVudF9pZDwvc3Bhbj46IElEIGZvciBpbmNpZGVudCwgdXNlZCB0byBsaW5rIHdlYXBvbiB0byBpbmNpZGVudC4NCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+d2VhcG9uX2lkPC9zcGFuPjogSUQgZm9yIHdlYXBvbiBpZGVudGlmaWNhdGlvbi4NCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+d2VhcG9uX3R5cGU8L3NwYW4+OiBUeXBlIG9mIHdlYXBvbi4NCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+Z3VuX2NsYXNzPC9zcGFuPjogQ2xhc3NpZmljYXRpb24gb2YgZ3VuIChIYW5kZ3VuLCBMb25nIGd1biwgVW5rbm93biBndW4gY2xhc3MsIE5vbi1ndW4pDQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPmd1bl90eXBlPC9zcGFuPjogVHlwZSBvZiBndW4gKGllLiBIYW5kZ3VuLCBQaXN0b2wsIFJldm9sdmVyLCBSaWZsZSwgZXRjLikNCg0KRmVhdHVyZXMoT2ZmZW5kZXJzIFsxNSBDb2x1bW5zIHggNzg4IFJvd3NdKToNCg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5pbmNpZGVudF9pZDwvc3Bhbj46IElEIG9mIGluY2lkZW50LCB1c2VkIHRvIGNvbm5lY3QgdGhlIDQgZGF0YSBzZXRzLg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5vZmZlbmRlcl9pZDwvc3Bhbj46IElEIHVzZWQgZm9yIGNsYXNzaWZpY2F0aW9uIG9mIG9mZmVuZGVycyAoTW9zdGx5IGZvciBtdWx0aS1vZmZlbmRlciBpbmNpZGVudHMpDQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPmZpcnN0bmFtZTwvc3Bhbj4NCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+bWlkZGxlbmFtZTwvc3Bhbj4NCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+bGFzdG5hbWU8L3NwYW4+DQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPnN1ZmZpeDwvc3Bhbj4NCi0gPHNwYW4gc3R5bGU9ImNvbG9yOmdyZWVuIj5hZ2U8L3NwYW4+DQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPnJhY2U8L3NwYW4+DQotIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPnNleDwvc3Bhbj4NCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+c3VpY2lkZTwvc3Bhbj46IFdoZXRoZXIgdGhlIG9mZmVuZGVyIGNvbW1pdGVkIHN1aWNpZGUgb3Igbm90Lg0KLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5kZWF0aGNhdXNlPC9zcGFuPjogV2hhdCBkaWQgdGhlIG9mZmVuZGVyIGRpZSBieSB3aGV0aGVyIGl0IHdhcyBzdWljaWRlIG9yIGtpbGxlZCBieSBhIGJ5c3RhbmRlci9wb2xpY2UNCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+b3V0Y29tZTwvc3Bhbj46IFdoYXQgd2FzIHRoZSBsZWdhbCBvdXRjb21lIGZvciB0aGUgaW5jaWRlbnQgKGllLiBBY3F1aXR0ZWQsIEFycmVzdGVkL1BlbmRpbmcgdHJpYWwsIENoYXJnZXMgZHJvcHBlZCwgZXRjLikNCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+Y3JpbWluYWxfanVzdGljZV9wcm9jZXNzPC9zcGFuPjogU3RhdHVzIG9mIGNyaW1pbmFsIGp1c3RpY2UgcHJvY2VzcyAoaWUuIEFycmVzdGVkL1BlbmRpbmcgdHJpYWwsIGNoYXJnZXMgZHJvcHBlZCwgZXRjLikNCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+c2VudGVuY2VfdHlwZTwvc3Bhbj46IFR5cGUgb2Ygc2VudGVuY2UgY29udmljdGVkIChpZS4gQWNxdWl0dGVkLCBBd2FpdGluZyBzZW50ZW5jaW5nLCBDb21taXR0ZWQsIERlYXRoIHNlbnRlbmNlIGV0Yy4pDQotIHNlbnRlbmNlX2RldGFpbHM6IERldGFpbHMgYWJvdXQgdGhlIHNlbnRlbmNlIGNvbnZpY3RlZC4NCg0KYGBge3J9DQpnbGltcHNlKGluY2lkZW50cykNCmBgYA0KDQoNCkZpbGxpbmcgaW4gYmxhbmsgaW5mb3JtYXRpb24gZm9yIGNsYXJpdHkuDQoNCmBgYHtyfQ0KdW5pcXVlKGluY2lkZW50cyRzaXR1YXRpb25fdHlwZSkNCg0KaW5jaWRlbnRzJHNpdHVhdGlvbl90eXBlW2luY2lkZW50cyRzaXR1YXRpb25fdHlwZSA9PSAiIl0gPC0gIlVua25vd24iDQoNCnVuaXF1ZShpbmNpZGVudHMkc2l0dWF0aW9uX3R5cGUpDQpgYGANCkhlcmUgaXMgYSBxdWljayBkaWFncmFtIG9mIHRoZSBVUyAoRXhjbHVkaW5nIEFsYXNrYSBhbmQgSGF3YWlpIGFzIGl0J3Mgbm90IHByb3Blcmx5IGZpdHRlZCkgdGhhdCBzaG93Y2FzZXMgd2hlcmUgYWxsIHRoZSBpbmNpZGVudHMgdG9vayBwbGFjZS4gVGhlIHBsYW4gaXMgZm9yIG1lIHRvIGV2ZW50dWFsbHkgYWxzbyB0dXJuIHRoaXMgaW50byBhIGhlYXQgbWFwIHRvIGdpdmUgYSBiZXR0ZXIgZ2F1Z2UgYXMgd2hlbiB0aGVyZSBhcmUgbXVsdGlwbGUgbGlrZSB0aGlzIGl0IGlzIGRpZmZpY3VsdCB0byBzaG93Y2FzZSBob3cgbXVjaCB0aGVyZSBpcyBkdWUgdG8gb3ZlcmxhcC4gSSBhbSBhbHNvIGF0dGVtcHRpbmcgdHdvIGRpZmZlcmVudCB3YXlzIG9mIHNob3dpbmcgdGhlIGRhdGEgcG9pbnRzLiBFdmVudHVhbGx5IEknbGwgZmlndXJlIG91dCB3aGljaCB3b3VsZCBiZSB0aGUgbW9zdCBlZmZlY3RpdmUgbWV0aG9kLg0KYGBge3J9DQp2YXJJIDwtIGluY2lkZW50cyAlPiUNCiAgc2VsZWN0KGMoaW5jaWRlbnRfaWQsIGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGZpcnN0Y29kLCBzaXR1YXRpb25fdHlwZSwgbG9jYXRpb24sIG51bV92aWN0aW1zX2tpbGxlZCwgbnVtX3ZpY3RpbXNfaW5qdXJlZCkpICU+JQ0KICByZW5hbWUobG9uID0gbG9uZ2l0dWRlKSAlPiUNCiAgcmVuYW1lKGxhdCA9IGxhdGl0dWRlKQ0KDQp2YXJJDQoNCnRyYW5zZm9ybWVkRGF0YSA8LSB1c21hcF90cmFuc2Zvcm0odmFySSkNCmBgYA0KDQoNCmBgYHtyfQ0KdGVtcERhdGEgPC0gdHJhbnNmb3JtZWREYXRhICU+JQ0KICBmaWx0ZXIocm93X251bWJlcigpICE9IDI2MikNCmBgYA0KDQpgYGB7cn0NCnBsb3RfdXNtYXAoKSArIGdlb21fc2YoDQogIGRhdGEgPSB0ZW1wRGF0YSwNCiAgYWVzKGNvbG9yID0gZmlyc3Rjb2QsIHNpemUgPSBudW1fdmljdGltc19raWxsZWQpLA0KICBhbHBoYSA9IC41KSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgJ21tJyksIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSwgZmFjZSA9ICJib2xkIikpICsNCiAgbGFicyh0aXRsZSA9ICJQUklNQVJZIHJlYXNvbiBmb3IgdmljdGltIGRlYXRocyIsIGNhcHRpb24gPSAiLVRoZSAyMDE3IExhcyBWZWdhcyBTaG9vdGVyIGhhcyBiZWVuIGV4Y2x1ZGVkIGZvciBjbGFyaXR5LiBUaGF0IGV2ZW50IGhhZCA2MCBkZWF0aHMgYW5kIDg2NyBpbmp1cmVkLiIpDQoNCmBgYA0KDQpgYGB7cn0NCnBsb3RfdXNtYXAoKSArIGdlb21fc2YoDQogIGRhdGEgPSB0ZW1wRGF0YSwNCiAgYWVzKGNvbG9yID0gZmlyc3Rjb2QsIHNpemUgPSBudW1fdmljdGltc19pbmp1cmVkKSwNCiAgYWxwaGEgPSAuNSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQua2V5LnNpemUgPSB1bml0KDEsICdtbScpLCBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUsIGZhY2UgPSAiYm9sZCIpKSArDQogIGxhYnModGl0bGUgPSAiUFJJTUFSWSByZWFzb24gZm9yIGluanVyZWQgdmljdGltcyIsIGNhcHRpb24gPSAiLVRoZSAyMDE3IExhcyBWZWdhcyBTaG9vdGVyIGhhcyBiZWVuIGV4Y2x1ZGVkIGZvciBjbGFyaXR5LiBUaGF0IGV2ZW50IGhhZCA2MCBkZWF0aHMgYW5kIDg2NyBpbmp1cmVkLiIpDQoNCmBgYA0KDQpgYGB7cn0NCnBsb3RfdXNtYXAoKSArIGdlb21fc2YoDQogIGRhdGEgPSB0ZW1wRGF0YSwNCiAgYWVzKGNvbG9yID0gbG9jYXRpb24sIHNpemUgPSBudW1fdmljdGltc19raWxsZWQpLA0KICBhbHBoYSA9IC41KSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgJ21tJyksIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSwgZmFjZSA9ICJib2xkIikpICsNCiAgbGFicyh0aXRsZSA9ICJMb2NhdGlvbiBhbmQgQW1vdW50IG9mIFZpY3RpbSBEZWF0aHMiLCBjYXB0aW9uID0gIi1UaGUgMjAxNyBMYXMgVmVnYXMgU2hvb3RlciBoYXMgYmVlbiBleGNsdWRlZCBmb3IgY2xhcml0eS4gVGhhdCBldmVudCBoYWQgNjAgZGVhdGhzIGFuZCA4NjcgaW5qdXJlZC4iKQ0KYGBgDQpgYGB7cn0NCnBsb3RfdXNtYXAoKSArIGdlb21fc2YoDQogIGRhdGEgPSB0ZW1wRGF0YSwNCiAgYWVzKGNvbG9yID0gbG9jYXRpb24sIHNpemUgPSBudW1fdmljdGltc19pbmp1cmVkKSwNCiAgYWxwaGEgPSAuNSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQua2V5LnNpemUgPSB1bml0KDEsICdtbScpLCBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUsIGZhY2UgPSAiYm9sZCIpKSArDQogIGxhYnModGl0bGUgPSAiTG9jYXRpb24gYW5kIEFtb3VudCBvZiBJbmp1cmVkIFZpY3RpbXMiLCBjYXB0aW9uID0gIi1UaGUgMjAxNyBMYXMgVmVnYXMgU2hvb3RlciBoYXMgYmVlbiBleGNsdWRlZCBmb3IgY2xhcml0eS4gVGhhdCBldmVudCBoYWQgNjAgZGVhdGhzIGFuZCA4NjcgaW5qdXJlZC4iKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdF91c21hcCgpICsgZ2VvbV9zZigNCiAgZGF0YSA9IHRlbXBEYXRhLA0KICBhZXMoY29sb3IgPSBzaXR1YXRpb25fdHlwZSwgc2l6ZSA9IG51bV92aWN0aW1zX2tpbGxlZCksDQogIGFscGhhID0gMC44KSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgJ21tJyksIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSwgZmFjZSA9ICJib2xkIikpICsNCiAgbGFicyh0aXRsZSA9ICJUeXBlIG9mIEluY2lkZW50IGFuZCBBbW91bnQgb2YgVmljdGltIERlYXRocyIsIGNhcHRpb24gPSAiLVRoZSAyMDE3IExhcyBWZWdhcyBTaG9vdGVyIGhhcyBiZWVuIGV4Y2x1ZGVkIGZvciBjbGFyaXR5LiBUaGF0IGV2ZW50IGhhZCA2MCBkZWF0aHMgYW5kIDg2NyBpbmp1cmVkLiIpDQoNCmBgYA0KYGBge3J9DQpwbG90X3VzbWFwKCkgKyBnZW9tX3NmKA0KICBkYXRhID0gdGVtcERhdGEsDQogIGFlcyhjb2xvciA9IHNpdHVhdGlvbl90eXBlLCBzaXplID0gbnVtX3ZpY3RpbXNfaW5qdXJlZCksDQogIGFscGhhID0gMC44KSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgJ21tJyksIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSwgZmFjZSA9ICJib2xkIikpICsNCiAgbGFicyh0aXRsZSA9ICJUeXBlIG9mIEluY2lkZW50IGFuZCBBbW91bnQgb2YgSW5qdXJlZCBWaWN0aW1zIiwgY2FwdGlvbiA9ICItVGhlIDIwMTcgTGFzIFZlZ2FzIFNob290ZXIgaGFzIGJlZW4gZXhjbHVkZWQgZm9yIGNsYXJpdHkuIFRoYXQgZXZlbnQgaGFkIDYwIGRlYXRocyBhbmQgODY3IGluanVyZWQuIikNCg0KYGBgDQoNCmBgYHtyfQ0KIyBHZXR0aW5nIGEgY291bnQgb2YgdGhlIGluY2lkZW50cyBwZXIgc3RhdGUNCnN0YXRlSW5jaWRlbnRzIDwtIGluY2lkZW50cyAlPiUNCiAgY291bnQoc3RhdGUpDQoNCiMgU2V0dGluZyBhIGZpbGwgY29sb3IgdmFyaWFibGUgZGVwZW5kZW50IG9uIHRoZSBudW1iZXIgb2YgaW5jaWRlbnRzDQpzdGF0ZUluY2lkZW50cyA8LSBzdGF0ZUluY2lkZW50cyAlPiUNCiAgbXV0YXRlKGZpbGxDb2xvciA9IGlmZWxzZShuPj00MCwgIjQwKyIsIGlmZWxzZShuPj0yMCwgIjIwLTM5IiwgIjAtMTkiKSkpDQpgYGANCg0KSGVyZSBpcyBhIGJhciBncmFwaCBzdGF0aXN0aWMgc2hvd2Nhc2luZyBhbGwgb2YgdGhlIGluY2lkZW50cyBmcm9tIHRoZSBkYXRhIHNldCBhbmQgc2hvd2luZyB0aGVtIGZyb20gbW9zdCB0byBsZWFzdCBpbiBhIGJhciBncmFwaCBmb3JtLiBGcm9tIHRoaXMgd2UgY2FuIHNlZSB0aGF0IENhbGlmb3JuaWEsIFRleGFzIGFuZCBJbGxpbm9pcyBhcmUgdGhlIHRocmVlIG1vc3QgZGFuZ2Vyb3VzIChpbiB0aGUgc2Vuc2Ugb2YgdGhlIG1vc3QgbWFzcyBtdXJkZXJzIG9jY3VyaW5nKSBsb2NhdGlvbnMgaW4gdGhlIFVTLiBGbG9yaWRhIGJlaW5nIGFuIGhvbm9yYWJsZSBtZW50aW9uIGZvciBmb3VydGggcGxhY2UuIEZyb20gaGVyZSBvbiBJIGNvdWxkIGFsc28gdGhlbiBmdXJ0aGVyIHRlc3QgdG8gY2hlY2sgdGhlIGFtb3VudCBvZiB2aWN0aW1zLCB3aGlsc3QgdGhpcyBncmFwaCBzaG93cyB0aGUgbW9zdCBtYXNzIGtpbGxpbmdzIGluIG9jY3VycmVuY2UgZm9yIHRoZSBwYXN0IH4yMCB5ZWFycywgdGhhdCBkb2VzIG5vdCBuZWNlc3NhcmlseSBwZXJ0YWluIHRvIGRlYWRsaW5lc3MgYXMgdGhlcmUgbWF5IGJlIG90aGVyIHN0YXRlcyB0aGF0IGhhdmUgbGVzcyBidXQgbW9yZSBzZXZlcmUgbWFzcyBtdXJkZXJzLg0KDQpgYGB7cn0NCiMgQ3JlYXRpbmcgdGhlIGdyYXBoIGFuZCBvcmdhbml6aW5nIGJ5IGFtb3VudA0KZ2dwbG90KHN0YXRlSW5jaWRlbnRzLCBhZXMoeCA9IHJlb3JkZXIoc3RhdGUsICtuKSwgeSA9IG4sIGZpbGwgPSBmaWxsQ29sb3IpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5Jywgd2lkdGggPSAwLjgpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAtMTkiID0gImdvbGQiLCAiMjAtMzkiID0gIm9yYW5nZSIsICI0MCsiID0gImRhcmtyZWQiKSkgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgaGp1c3QgPSAxKSkgKw0KICBsYWJzKHRpdGxlID0gIlRvdGFsIEluY2lkZW50cyBQZXIgU3RhdGUiLCB4ID0gIlN0YXRlcyIsIHkgPSAiQW1vdW50IG9mIEluY2lkZW50cyIpICsNCiAgY29vcmRfZmxpcCgpDQpgYGANCmBgYHtyfQ0KIyBHZXR0aW5nIGEgc3VtIG9mIHRoZSBhbW91bnQgb2YgYm90aCB2aWN0aW1zIGtpbGxlZCBhbmQgaW5qdXJlZCBwZXIgc3RhdGUNCmRlYWRseW5lc3NQZXJTdGF0ZSA8LSBpbmNpZGVudHMgJT4lDQogIGdyb3VwX2J5KHN0YXRlKSAlPiUNCiAgc3VtbWFyaXplKHRvdGFsRGVhdGhzID0gc3VtKG51bV92aWN0aW1zX2tpbGxlZCksIHRvdGFsSW5qdXJlZCA9IHN1bShudW1fdmljdGltc19pbmp1cmVkKSkNCg0KIyBOb3cgYXBwbHlpbmcgYSBtYW51YWwgZmlsbCB2YXJpYWJsZSB0byBiZSBhYmxlIHRvIGFwcGx5IHRvIHRoZSBncmFwaCBsYXRlcg0KZGVhZGx5bmVzc1BlclN0YXRlIDwtIGRlYWRseW5lc3NQZXJTdGF0ZSAlPiUNCiAgbXV0YXRlKGZpbGxDb2xvckRlYXRoID0gaWZlbHNlKHRvdGFsRGVhdGhzPj0yMDAsICIyMDArIiwgaWZlbHNlKHRvdGFsRGVhdGhzPj0xMDAsICIxMDAtMTk5IiwgIjAtOTkiKSksDQogICAgICAgICBmaWxsQ29sb3JJbmp1cnkgPSBpZmVsc2UodG90YWxJbmp1cmVkPj0yMDAsICIyMDArIiwgaWZlbHNlKHRvdGFsSW5qdXJlZD49MTAwLCAiMTAwLTE5OSIsICIwLTk5IikpKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRlYWRseW5lc3NQZXJTdGF0ZSwgYWVzKHggPSByZW9yZGVyKHN0YXRlLCArdG90YWxEZWF0aHMpLCB5ID0gdG90YWxEZWF0aHMsIGZpbGwgPSBmaWxsQ29sb3JEZWF0aCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScsIHdpZHRoID0gMC44KSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAtOTkiID0gImdvbGQiLCAiMTAwLTE5OSIgPSAib3JhbmdlIiwgIjIwMCsiID0gImRhcmtyZWQiKSkgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgaGp1c3QgPSAxKSkgKw0KICBsYWJzKHRpdGxlID0gIlRvdGFsIFZpY3RpbSBEZWF0aHMgUGVyIFN0YXRlIiwgeCA9ICJTdGF0ZXMiLCB5ID0gIkFtb3VudCBvZiBEZWF0aHMiKSArDQogIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRlYWRseW5lc3NQZXJTdGF0ZSwgYWVzKHggPSByZW9yZGVyKHN0YXRlLCArdG90YWxJbmp1cmVkKSwgeSA9IHRvdGFsSW5qdXJlZCwgZmlsbCA9IGZpbGxDb2xvckluanVyeSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScsIHdpZHRoID0gMC44KSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAtOTkiID0gImdvbGQiLCAiMTAwLTE5OSIgPSAib3JhbmdlIiwgIjIwMCsiID0gImRhcmtyZWQiKSkgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgaGp1c3QgPSAxKSkgKw0KICBsYWJzKHRpdGxlID0gIlRvdGFsIEluanVyZWQgVmljdGltcyBQZXIgU3RhdGUiLCB4ID0gIlN0YXRlcyIsIHkgPSAiQW1vdW50IG9mIEluanVyZWQiKSArDQogIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCg0KYGBge3J9DQpnZ3Bsb3Qod2VhcG9ucywgYWVzKHggPSB3ZWFwb25fdHlwZSkpICsNCiAgZ2VvbV9iYXIod2lkdGggPSAwLjgpDQpgYGANCg0KV2l0aCB0aGlzIFZpb2xpbiBwbG90ICgrIEJveHBsb3QpIHdlIGNhbiBzZWUgdGhlIGdlbmVyYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSB2aWN0aW1zIGFzIHdlbGwgYXMgdGhlIG1lZGlhbnMuIEdlbmVyYWxseSBpdCBzZWVtcyB0aGF0IGZlbWFsZXMgYW5kIG1hbGVzIGFyZSBib3RoIG9uIGF2ZXJhZ2Ugbm90IHRvbyBkaXNzaW1pbGFyIGJ1dCB0aGlzIGlzIHdpdGhvdXQga25vd2luZyB0aGUgZXhhY3QgYW1vdW50IG9mIG51bWJlcnMuIFByb3BvcnRpb25hbGx5IGhvd2V2ZXIsIHRoZSBhZ2Ugb2Ygd2hpY2ggdGhleSBkaWVkIGRvZXMgbm90IHNlZW0gdG8gbWF0dGVyIGRlc3BpdGUgdGhlIHNleC4gVGhlIHVua25vd24gc2VlbXMgdG8gYmUgY2FzZXMgd2hpY2ggdGhlIGJvZGllcyB3ZXJlIHJlY292ZXJlZCBidXQgbWF5YmUgbm90IGFibGUgdG8gYmUgaWRlbnRpZmllZCBhcyB0aGVzZSBjYXNlcyBoYXZlIGxpdHRsZSB0byBubyBpbmZvcm1hdGlvbiB0byB0aGVtDQoNCmBgYHtyfQ0KZ2dwbG90KHZpY3RpbXMsIGFlcyh4ID0gc2V4LCB5ID0gYWdlLCBmaWxsID0gc2V4KSkgKw0KICBnZW9tX3Zpb2xpbih0cmltID0gRkFMU0UpICsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC40KSArDQogIGdlb21faml0dGVyKHNoYXBlID0gMTYsIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcigwLjEpLCBhbHBoYSA9IDAuMikNCmBgYA0KDQoNCkkgc3BlY2lmaWNhbGx5IHJlbWVtYmVyIHRoaXMgb2NjdXJyZW5jZSwgSSByZWNhbGwgaXQgYmVpbmcgZXZlcnl3aGVyZSBvbiB0aGUgbmV3cyBhbmQgc28gSSB0ZXN0ZWQgb3V0IHRoZSBJRCBhbmQgc2VlaW5nIGhvdyB3ZWxsIEkgY291bGQgZXh0cmFjdCB0aGUgZGF0YS4gDQoNCmBgYHtyfQ0KDQppbmNpZGVudHNGTCA8LSBpbmNpZGVudHMgJT4lDQogIGZpbHRlcihzdGF0ZSA9PSAiRkwiKQ0KDQppbmNpZGVudHNGTA0KDQp3ZWFwb25zICU+JQ0KICBmaWx0ZXIoaW5jaWRlbnRfaWQgPT0gMzAwKQ0KDQp2aWN0aW1zICU+JQ0KICBmaWx0ZXIoaW5jaWRlbnRfaWQgPT0gMzAwKQ0KDQpvZmZlbmRlcnMgJT4lDQogIGZpbHRlcihpbmNpZGVudF9pZCA9PSAzMDApDQpgYGANCg0KDQpIZXJlIEkgd2FzIGNoZWNraW5nIGlmIHRoZXJlIGFyZSBhbnkgb3RoZXIgZGlzY3JpbWluYXRvcnkgYXR0YWNrcyBhZ2FpbnN0IGdheSBwZW9wbGUgc2VhcmNoaW5nIHRocm91Z2ggdGhlIG5hcnJhdGl2ZXMgZm9yIHRoZSB0ZXJtICJnYXkiLCBzdXJwcmlzaW5nbHksIG91dCBvZiBhbGwgdGhlIG9uZXMgaW4gdGhlIFVTIG9ubHkgb25lIHNob3dlZCB1cCwgd2hpY2ggaXMgdGhlIHNhbWUgb25lIGZyb20gYWJvdmUgdGhhdCBvY2N1cnJlZCBpbiBPcmxhbmRvLg0KDQpgYGB7cn0NCiMgV2l0aCBncmVwbCBJIGNhbiBzZWFyY2ggZm9yIHNwZWNpZmljIHdvcmRzIGluIHRoZSBuYXJyYXRpdmUgb3IgYW55IG90aGVyIG9mIHRoZSBzdHJpbmdzIG9mIHRleHRzIHRoYXQgZ2l2ZSBuYXJyYXRpdmVzLg0KaW5jaWRlbnRzICU+JQ0KICBmaWx0ZXIoZ3JlcGwoImdheSIsIG5hcnJhdGl2ZSkpDQoNCmBgYA0KDQpgYGB7cn0NCg0KYGBgDQoNCkkgd291bGQgY29uc2lkZXIgdGhpcyBkYXRhIHNldCB0byBiZSAqcmVsYXRpdmVseSogY2xlYW4uIEJ1dCwgdGhlcmUgYXJlIHNvbWUgdGhpbmdzIHRoYXQgY291bGQgYmUgYWx0ZXJlZCBmb3IgdGhlIHNha2Ugb2Ygd29ya2luZyB3aXRoIHRoZW0uIEZvciBleGFtcGxlLCB0aGVyZSBhcmUgYSBsb3Qgb2YgTlVMTCBjZWxscyBidXQgZHVlIHRvIHRoZSB0eXBlIG9mIGRhdGEgSSBkbyBub3QgcGxhbiB0byByZW1vdmUgdGhlc2Ugcm93cywgSSB3aWxsIGhvd2V2ZXIgcHJvYmFibHkgY2hhbmdlIHRoZW0gaW50byAiTi9BIiBvciBzb21ldGhpbmcgb2YgdGhlIHNvcnQgYXMgdGhleSBhcmUgaW1wb3J0YW50LiBUaGVyZSBhcmUgc29tZSBmZWF0dXJlcywgZm9yIGV4YW1wbGUgLSBzaXR1YXRpb25fdHlwZSwgd2hpY2ggaGFzICJVbmRldGVybWluZXMiIGFuZCBqdXN0IGZsYXQgb3V0IE51bGwuIFJlYWRpbmcgdGhyb3VnaCB0aGUgbmFycmF0aXZlcywgbXkgcGVyc29uYWwgYmVsaWVmIGlzIHRoYXQgdGhlc2UgYXJlIG1vc3QgbGlrZWx5IGluY2lkZW50cyBpbiB3aGljaCB0aGVyZSB3YXMgc2ltcGx5IG5vIG9mZmljaWFsIHN0YXRlbWVudCBvZiB3aGF0IHR5cGUgb2Ygc2l0dWF0aW9uIHRoZSBpbmNpZGVudCB3YXMuIFRoaXMgd291bGQgYmUgYSBzaXR1YXRpb24gaW4gd2hpY2ggSSB3b3VsZCBhbHRlciB0aGUgZGF0YSB0byBvZmZpY2lhbGx5IHN0YXRlIHNvbWV0aGluZyBsaWtlICJOb3QgU3RhdGVkIiANCg0KDQoNCkRpc2N1c3Npb246DQoNCk15IGdlbmVyYWwgaW1wcmVzc2lvbiBvbiB0aGlzIGRhdGEgc2V0IGlzIHRoYXQgd2hpbGUgaXQgaXMgdmVyeSBpbnRlcmVzdGVkLCBhdCBsZWFzdCBmb3IgbWUsIGl0IGRvZXMgcG9zZSB0aGUgY2hhbGxlbmdlIG9mIGF0dGVtcHRpbmcgdG8gZG8gYW55IHNvcnQgb2YgcHJlZGljdGlvbnMuIEEgbG90IG9mIHRoaXMgZGF0YSBpcyBzaW1wbHkgZmFjdCBidXQgYmVjYXVzZSBvZiB0aGUgbmF0dXJlIG9mIHRoZSBkYXRhIEkgY2Fubm90IHNlZW0gdG8gZG8gYW55IHNvcnQgb2YgdGltZSBzZXJpZXMgZGF0YSBhcyB0aGUgZGF0ZXMgY291bGQgYmUgY29uc2lkZXJlZCBhcyBjb250aW51b3VzIGJ1dCB0aGUgc2l0dWF0aW9ucyBhcmUgc2VwYXJhdGUgYW5kIG5vdCBsaW5rZWQgdG9nZXRoZXIuDQoNClJlZ2FyZGluZyB0aGUgdHlwZSBvZiBtb2RlbHMsIEknbSB0aGlua2luZyBvZiBtYXliZSB1c2luZyBhIHR5cGUgb2YgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdG8gc2VlIGlmIG1heWJlIHRoZXJlIGlzIGFueSBjb3JyZWxhdGlvbiB3aXRoIGNlcnRhaW4gZmVhdHVyZXMgdG8gZGV0ZXJtaW5lL3ByZWRldGVybWluZSB0aGUgcG90ZW50aWFsIGxldGhhbGl0eSBvZiBhIHNpdHVhdGlvbiBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb24gaXQgaGFzIGdpdmVuIHVzLiBUaGlzIHdvdWxkIGJlIHRyaWNreSBhcyB0aGluZ3MgbGlrZSByYWNlIGFuZCBhZ2UgYXJlIHRvbyBicm9hZCBhbmQgb3RoZXIgZmVhdHVyZXMgbGlrZSBzaXR1YXRpb25fdHlwZSBhcmUgZ2VuZXJhbGx5IGhhcmQgdG8gZ2FndWUgYmVmb3JlIHRoZSBzaXR1YXRpb24gaGFzIGFscmVhZHkgZXNjYWxhdGVkLiBUaGF0IHNhaWQgSSdsbCBhdHRlbXB0IHRvIGF0IGxlYXN0IHNlZSB3aGF0IEkgd291bGQgYmUgYWJsZSB0byBwcmVkaWN0IGxpa2UgbWF5YmUgd2hhdCB0aGUgb2RkcyBhcmUgb2Ygc3Vydml2YWwgd2l0aCBzcGVjaWZpYyBib2R5IHR5cGVzIChhZ2UsIHNleCwgcmFjZSwgZXRjLikgaGF2ZSBpbiB0aGVpciByZXNwZWN0aXZlIHNpdHVhdGlvbnMuIFRoaXMgY291bGQgYmUgZG9uZSB3aXRoIHRoZSB1c2FnZSBvZiBsaW5lYXIgcmVncmVzc2lvbi4gDQoNCmBgYHtyfQ0KZnVsbE1lcmdlZCA9IDANCmZ1bGxNZXJnZWQgPC0gZnVsbF9qb2luKGluY2lkZW50cywgb2ZmZW5kZXJzLCBieSA9ICJpbmNpZGVudF9pZCIpDQpmdWxsTWVyZ2VkIDwtIGZ1bGxfam9pbihmdWxsTWVyZ2VkLCB2aWN0aW1zLCBieSA9ICJpbmNpZGVudF9pZCIpDQpmdWxsTWVyZ2VkIDwtIGZ1bGxfam9pbihmdWxsTWVyZ2VkLCB3ZWFwb25zLCBieSA9ICJpbmNpZGVudF9pZCIpDQoNCiMgeCA9IE9mZmVuZGVyLCB5ID0gVmljdGltDQpmdWxsTWVyZ2VkQ2xlYW4gPC0gc3Vic2V0KGZ1bGxNZXJnZWQsIHNlbGVjdCA9IC1jKGluY2lkZW50X2lkLCBsb2NhdGlvbl90eXBlLCBsb25naXR1ZGUsIGxhdGl0dWRlLCBjZW5zdXNfdHJhY3RfZ2VvaWQsIG5hcnJhdGl2ZSwgZmlyc3RuYW1lLCBsYXN0bmFtZSwgbWlkZGxlbmFtZSwgc3VmZml4LCBkZWF0aGNhdXNlLCBvdXRjb21lLCBjcmltaW5hbF9qdXN0aWNlX3Byb2Nlc3MsIHNlbnRlbmNlX3R5cGUsIHNlbnRlbmNlX2RldGFpbHMsIHZpY3RpbV9pZCwgd2VhcG9uX2lkLCBvZmZlbmRlcl9pZCwgdHlwZSkpDQpgYGANCg0KYGBge3J9DQpmdWxsTWVyZ2VkQ2xlYW4kaGFkX3N1cnZpdm9yIDwtIGlmZWxzZShmdWxsTWVyZ2VkQ2xlYW4kbnVtX3ZpY3RpbXNfaW5qdXJlZCA+IDAsICJZZXMiLCAiTm8iKQ0KZnVsbE1lcmdlZENsZWFuJGhhZF9zdXJ2aXZvciA8LSBhcy5mYWN0b3IoZnVsbE1lcmdlZENsZWFuJGhhZF9zdXJ2aXZvcikNCmBgYA0KDQpgYGB7cn0NCnVuaXF1ZShmdWxsTWVyZ2VkQ2xlYW4pDQoNCmZ1bGxNZXJnZWRDbGVhbiRkYXRlIDwtIHltZChmdWxsTWVyZ2VkQ2xlYW4kZGF0ZSkNCmZ1bGxNZXJnZWRDbGVhbiR5ZWFyIDwtIHllYXIoZnVsbE1lcmdlZENsZWFuJGRhdGUpDQpmdWxsTWVyZ2VkQ2xlYW4kbW9udGggPC0gbW9udGgoZnVsbE1lcmdlZENsZWFuJGRhdGUpDQpmdWxsTWVyZ2VkQ2xlYW4kZGF5IDwtIGRheXMoZnVsbE1lcmdlZENsZWFuJGRhdGUpDQpmdWxsTWVyZ2VkQ2xlYW4kd2Vla2RheSA8LSB3ZWVrZGF5cyhmdWxsTWVyZ2VkQ2xlYW4kZGF0ZSkNCg0KZmFjdG9yQ29sIDwtIGMoIndlZWtkYXkiLCAiY2l0eSIsICJzdGF0ZSIsICJmaXJzdGNvZCIsICJzZWNvbmRjb2QiLCAiaWZfYXNzYXVsdF9yaWZsZV91c2VkIiwgInNpdHVhdGlvbl90eXBlIiwgImxvY2F0aW9uIiwgImNvdW50eSIsICJyYWNlLngiLCAic2V4LngiLCAicmFjZS55IiwgInNleC55IiwgInZvcmVsYXRpb25zaGlwIiwgIndlYXBvbl90eXBlIiwgIndlYXBvbl90eXBlIiwgImd1bl9jbGFzcyIsICJndW5fdHlwZSIpDQoNCmZ1bGxNZXJnZWRDbGVhbiA8LSBmdWxsTWVyZ2VkQ2xlYW4gfD4NCiAgbXV0YXRlKGFjcm9zcyhhbGxfb2YoZmFjdG9yQ29sKSwgYXMuZmFjdG9yKSkNCg0KZnVsbE1lcmdlZENsZWFuJHN1aWNpZGUgPC0gYXMubnVtZXJpYyhmdWxsTWVyZ2VkQ2xlYW4kc3VpY2lkZSkNCg0KdGVzdE1lcmdlIDwtIHN1YnNldChmdWxsTWVyZ2VkQ2xlYW4sIHNlbGVjdCA9IGMod2Vla2RheSwgc3RhdGUsIG51bV9vZmZlbmRlcnMsIG51bV92aWN0aW1zX2tpbGxlZCwgbnVtX3ZpY3RpbXNfaW5qdXJlZCwgZmlyc3Rjb2QsIHNlY29uZGNvZCwgaWZfYXNzYXVsdF9yaWZsZV91c2VkLCBzaXR1YXRpb25fdHlwZSwgbG9jYXRpb24sIGFnZS54LCByYWNlLngsIHNleC54LCBhZ2UueSwgcmFjZS55LCBzZXgueSwgdm9yZWxhdGlvbnNoaXAsIHdlYXBvbl90eXBlLCBndW5fY2xhc3MsIGd1bl90eXBlLCBoYWRfc3Vydml2b3IpKQ0KDQp0ZXN0TWVyZ2UNCmBgYA0KDQoNCmBgYHtyfQ0KbGRhVGVzdE1vZGVsIDwtIGxkYShoYWRfc3Vydml2b3IgfiAuLCBkYXRhID0gdGVzdE1lcmdlKQ0Kc3VtbWFyeShsZGFUZXN0TW9kZWwpDQoNCmNvcih0ZXN0TWVyZ2UpDQpgYGANCg0KYGBge3J9DQppbmNpZGVudHMNCm9mZmVuZGVycw0KdmljdGltcw0Kd2VhcG9ucw0KYGBgDQoNCkZFQVRVUkUgRU5HSU5FRVIsIEdPSU5HIFRPIE1FUkdFIEVWRVJZVEhJTkcNCkZlYXR1cmVzIHdhbnRlZA0KaW5jaWRlbnRfaWQsIGRhdGUsIHN0YXRlLCBudW1fb2ZmZW5kZXJzLCBudW1fdmljdGltc19raWxsZWQsIG51bV92aWN0aW1zX2luanVyZWQsIGZpcnN0Y29kLCBpZl9hc3NhdWx0X3JpZmxlX3VzZWQsIHNpdHVhdGlvbl90eXBlLCBsb2NhdGlvbiwgb2ZmZW5kZXJfYWdlLCBvZmZlbmRlcl9yYWNlLCBvZmZlbmRlcl9zZXgsIHZpY3RpbV9hZ2UsIHZpY3RpbV9zZXgsIHZvcmVsYXRpb25zaGlwLCB3ZWFwb25fdHlwZQ0KDQpBREQNCm51bV92aWN0aW1zX3RvdGFsDQoNClR1cm4gQ2F0ZWdvcmljYWwgaW50byBkdW1teSB2YXJpYWJsZXMNCg0KYGBge3J9DQojIEZpeGluZyB0aGUgZGF0ZSBhbmQgYWRkaW5nIGV4dHJhIGRhdGUgY29sdW1ucy4NCmluY2lkZW50c1VwZGF0ZWQgPC0gaW5jaWRlbnRzICU+JQ0KICBtdXRhdGUoDQogICAgZGF0ZSA9IGFzLkRhdGUoZGF0ZSksDQogICAgeWVhciA9IHllYXIoZGF0ZSksDQogICAgbW9udGggPSBtb250aChkYXRlKSwNCiAgICBkYXkgPSBkYXkoZGF0ZSksDQogICAgd2Vla2RheSA9IHdlZWtkYXlzKGRhdGUpDQogICkNCg0KaW5jaWRlbnRzVXBkYXRlZCA8LSBuYS5vbWl0KGluY2lkZW50c1VwZGF0ZWQpDQoNCmluY2lkZW50c1VwZGF0ZWQkaGFkX3N1cnZpdm9yIDwtIGlmZWxzZShpbmNpZGVudHNVcGRhdGVkJG51bV92aWN0aW1zX2luanVyZWQgPiAwLCAiWWVzIiwgIk5vIikNCmluY2lkZW50c1VwZGF0ZWQkaGFkX3N1cnZpdm9yIDwtIGFzLmZhY3RvcihpbmNpZGVudHNVcGRhdGVkJGhhZF9zdXJ2aXZvcikNCg0KIyBbTmFtZV0gU3VtbWFyaWVzLCB0aGVzZSB3aWxsIGdldCBhbGwgdGhlIGNvbHVtbnMgdGhhdCB3aWxsIGJlIHVzZWQgZm9yIHRoZSBtb2RlbHMuDQppbmNpZGVudHNTdW0gPC0gaW5jaWRlbnRzVXBkYXRlZCAlPiUNCiAgc3Vic2V0KHNlbGVjdCA9IGMoaW5jaWRlbnRfaWQsIGRhdGUsIHllYXIsIG1vbnRoLCBkYXksIHdlZWtkYXksIHN0YXRlLCBudW1fb2ZmZW5kZXJzLCBudW1fdmljdGltc19raWxsZWQsIG51bV92aWN0aW1zX2luanVyZWQsIGZpcnN0Y29kLCBzaXR1YXRpb25fdHlwZSwgbG9jYXRpb24sIGhhZF9zdXJ2aXZvcikpDQoNCm9mZmVuZGVyU3VtIDwtIG9mZmVuZGVycyAlPiUNCiAgc3Vic2V0KHNlbGVjdCA9IGMoaW5jaWRlbnRfaWQsIG9mZmVuZGVyX2lkLCBhZ2UsIHJhY2UsIHNleCkpICU+JQ0KICByZW5hbWUob2ZmZW5kZXJBZ2UgPSBhZ2UpICU+JQ0KICByZW5hbWUob2ZmZW5kZXJSYWNlID0gcmFjZSkgJT4lDQogIHJlbmFtZShvZmZlbmRlclNleCA9IHNleCkNCg0KdmljdGltU3VtIDwtIHZpY3RpbXMgJT4lDQogIHN1YnNldChzZWxlY3QgPSBjKGluY2lkZW50X2lkLCB2aWN0aW1faWQsIGFnZSwgcmFjZSwgc2V4LCB2b3JlbGF0aW9uc2hpcCkpICU+JQ0KICByZW5hbWUodmljdGltQWdlID0gYWdlKSAlPiUNCiAgcmVuYW1lKHZpY3RpbVJhY2UgPSByYWNlKSAlPiUNCiAgcmVuYW1lKHZpY3RpbVNleCA9IHNleCkNCg0Kd2VhcG9uU3VtIDwtIHdlYXBvbnMgJT4lDQogIHN1YnNldChzZWxlY3QgPSBjKGluY2lkZW50X2lkLCB3ZWFwb25faWQsIHdlYXBvbl90eXBlKSkNCg0KIyBNZXJnaW5nIHRoZSBkYXRhDQp0b3RhbERhdGEgPC0gaW5jaWRlbnRzU3VtICU+JQ0KICBsZWZ0X2pvaW4ob2ZmZW5kZXJTdW0sIGJ5ID0gImluY2lkZW50X2lkIikgJT4lDQogIGxlZnRfam9pbih2aWN0aW1TdW0sIGJ5ID0gImluY2lkZW50X2lkIikgJT4lDQogIGxlZnRfam9pbih3ZWFwb25TdW0sIGJ5ID0gImluY2lkZW50X2lkIikNCg0KdG90YWxEYXRhIDwtIG5hLm9taXQodG90YWxEYXRhKQ0KdG90YWxEYXRhDQpgYGANCg0KYGBge3J9DQojIExpc3Qgb2YgY29sdW1uIG5hbWVzIEkgbmVlZCB0byBmYWN0b3JpemUNCmNoYXJFbmNvZGUgPC0gYygid2Vla2RheSIsICJzdGF0ZSIsICJmaXJzdGNvZCIsICJzaXR1YXRpb25fdHlwZSIsICJsb2NhdGlvbiIsICJvZmZlbmRlclJhY2UiLCAib2ZmZW5kZXJTZXgiLCAidmljdGltUmFjZSIsICJ2aWN0aW1TZXgiLCAidm9yZWxhdGlvbnNoaXAiLCAid2VhcG9uX3R5cGUiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBUdXJucyBhbnkgYmxhbmsgY2VsbHMgdG8gIlVua25vd24iDQp0b3RhbERhdGFbdG90YWxEYXRhID09ICIiXSA8LSAiVW5rbm93biINCg0KI2FueShpcy5uYSh0b3RhbERhdGEpKQ0KDQojIFRoaXMgd2lsbCBmYWN0b3JpemUgYWxsIG9mIHRoZSBkYXRhIGluc3RlYWQgb2YgaGF2aW5nIHRvIG1hbnVhbGx5IGRvIGl0DQp0b3RhbERhdGFGYWN0b3JlZCA8LSB0b3RhbERhdGEgJT4lDQogIG11dGF0ZShhY3Jvc3MoYWxsX29mKGNoYXJFbmNvZGUpLCB+IGFzLmludGVnZXIoZmFjdG9yKC54KSkpKQ0KYGBgDQoNCmBgYHtyfQ0KIyBTdW1zIHRoZSBtYXggdmFsdWUgaW4gYWxsIG9mIHRoZSBjb2x1bW5zIHdoaWNoIHNob3VsZCwgaW4gdGhlb3J5LCBnaXZlIHRoZSB0b3RhbCBhbW91bnQgb2YgZGlzdGluY3QgY29sdW1ucyBJIHNob3VsZCBoYXZlLg0Kc3VtKHNhcHBseSh0b3RhbERhdGFGYWN0b3JlZFtjaGFyRW5jb2RlXSwgbWF4KSkNCg0KIyBHZXQgYWxsIG9mIHRoZSBuYW1lcyBhbmQgd2hpY2ggY29sdW1uIHRoZXkgd2VyZSBmcm9tDQpmYWN0b3JMb29rdXAgPC0gdG90YWxEYXRhICU+JQ0KICBkcGx5cjo6c2VsZWN0KGNoYXJFbmNvZGUpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIk9yaWdpbiIsDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiTmFtZSIpIA0KDQojIEdhdGhlcnMgYWxsIG9mIHRoZSBmYWN0b3JlZCBkYXRhDQpmYWN0b3JMb29rdXAyIDwtIHRvdGFsRGF0YUZhY3RvcmVkICU+JQ0KICBkcGx5cjo6c2VsZWN0KGNoYXJFbmNvZGUpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gTlVMTCwNCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJFbmNvZGVkIFZhbHVlIikNCg0KIyBBc3N1bWluZyBub3RoaW5nIGhhcyBjaGFuZ2VkIGFuZCBoYXZpbmcgY2hlY2tlZCB0aGUgbnVtYmVyIGl0IG1hdGNoZXMgdXAuIEkgYXNzdW1lIHRoaXMgaXMgY29ycmVjdCBhbmQgbm93IGZhY3Rvckxvb2t1cCBpcyBhIGdvb2QgZGljdGlvbmFyeSB0byBnbyBiYWNrIHRvLg0KZmFjdG9yTG9va3VwIDwtIGNiaW5kKGZhY3Rvckxvb2t1cCwgZmFjdG9yTG9va3VwMikNCmZhY3Rvckxvb2t1cCA8LSBkaXN0aW5jdChmYWN0b3JMb29rdXApDQpmYWN0b3JMb29rdXANCmBgYA0KDQpgYGB7cn0NCnNwbGl0RGF0YSA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGJpbmFyeUZhY3RvcmVkJGhhZF9zdXJ2aXZvciwgcCA9IDAuOCwgbGlzdCA9IEZBTFNFKQ0KdHJhaW5EYXRhIDwtIGJpbmFyeUZhY3RvcmVkW3NwbGl0RGF0YSwgXQ0KdGVzdERhdGEgPC0gYmluYXJ5RmFjdG9yZWRbLXNwbGl0RGF0YSwgXQ0KYGBgDQoNCg0KYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA4fQ0KIyBUaGlzIGlzIHNvIHRoYXQgSSBjYW4gdXNlIGl0IGluIHRoZSBjb3JyIG1hdHJpeCBidXQgYWxzbyBtYWtlIG15IGxpZmUgZWFzaWVyDQp0b3RhbERhdGFGYWN0b3JlZEZvclJlYWwgPC0gc3Vic2V0KHRvdGFsRGF0YUZhY3RvcmVkLCBzZWxlY3QgPSAtYyhpbmNpZGVudF9pZCwgZGF0ZSwgeWVhciwgbW9udGgsIG9mZmVuZGVyX2lkLCB2aWN0aW1faWQpKQ0KdG90YWxEYXRhRmFjdG9yZWRGb3JSZWFsJGhhZF9zdXJ2aXZvciA8LSBhcy5udW1lcmljKHRvdGFsRGF0YUZhY3RvcmVkRm9yUmVhbCRoYWRfc3Vydml2b3IpDQoNCiMgTGluZWFyIFJlZ3Jlc3Npb24gTW9kZWwNCmxpbk1vZGVsIDwtIGxtKGhhZF9zdXJ2aXZvciB+IC4sIGRhdGEgPSB0b3RhbERhdGFGYWN0b3JlZEZvclJlYWwpDQpzdW1tYXJ5KGxvZ01vZGVsKQ0KDQpjb3JNIDwtIGNvcih0b3RhbERhdGFGYWN0b3JlZEZvclJlYWwpDQpjb3JycGxvdChjb3JNLCBtZXRob2QgPSAiY29sb3IiKQ0KaGVhdG1hcChjb3JNLCBzeW1tID0gVFJVRSwgbWFpbiA9ICJDb3JyZWxhdGlvbiBIZWF0bWFwIikNCmBgYA0KDQpgYGB7cn0NCiMgSy1Gb2xkIFRyYWluIENvbnRyb2wNCnNldC5zZWVkKDc4OSkNCnRyYWluX2NvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJyZXBlYXRlZGN2IiwgbnVtYmVyID0gMTAsIHJlcGVhdHMgPSAzLCBjbGFzc1Byb2JzID0gVFJVRSwgc3VtbWFyeUZ1bmN0aW9uID0gdHdvQ2xhc3NTdW1tYXJ5LCB2ZXJib3NlSXRlciA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KYmluYXJ5RmFjdG9yZWQgPC0gc3Vic2V0KHRvdGFsRGF0YUZhY3RvcmVkLCBzZWxlY3QgPSAtYyhpbmNpZGVudF9pZCwgZGF0ZSwgeWVhciwgbW9udGgsIG9mZmVuZGVyX2lkLCB2aWN0aW1faWQpKQ0KYmluYXJ5RmFjdG9yZWQkaGFkX3N1cnZpdm9yIDwtIGZhY3Rvcih0b3RhbERhdGFGYWN0b3JlZCRoYWRfc3Vydml2b3IsIGxldmVscyA9IGMoIlllcyIsICJObyIpKQ0KYmluYXJ5RmFjdG9yZWQNCg0KdGFibGUoYmluYXJ5RmFjdG9yZWQkaGFkX3N1cnZpdm9yKQ0KDQpyZk1vZGVsIDwtIHRyYWluKGhhZF9zdXJ2aXZvciB+IC4gLWhhZF9zdXJ2aXZvciAtbnVtX3ZpY3RpbXNfa2lsbGVkIC1udW1fdmljdGltc19pbmp1cmVkLCBkYXRhID0gYmluYXJ5RmFjdG9yZWQsIG1ldGhvZCA9ICJyZiIsIHRyQ29udHJvbCA9IHRyYWluX2NvbnRyb2wsIG50cmVlID0gNTAwKQ0KcHJpbnQocmZNb2RlbCkNCg0KYGBgDQoNCg0KYGBge3J9DQojIExvZ2lzdGljIFJlZ3Jlc3Npb246IENyZWF0aW5nIHRoZSBpbml0aWFsIG1vZGVsDQpsb2dNb2RlbCA8LSBnbG0oaGFkX3N1cnZpdm9yfiAuIC1udW1fdmljdGltc19raWxsZWQgLW51bV92aWN0aW1zX2luanVyZWQgLWhhZF9zdXJ2aXZvciwgZGF0YSA9IHRyYWluRGF0YSwgZmFtaWx5ID0gImJpbm9taWFsIikNCg0KIyBBcHBseWluZyBzdGVwd2lzZQ0Kc3RlcExvZ01vZGVsIDwtIHN0ZXAobG9nTW9kZWwsIGRpcmVjdGlvbiA9ICJib3RoIikNCg0KIyBUcmFpbmluZyB0aGUgc3RlcHdpc2Ugb24ga0NWDQpzdGVwTG9nTW9kZWxDViA8LSB0cmFpbihoYWRfc3Vydml2b3IgfiAuIC1udW1fdmljdGltc19raWxsZWQgLW51bV92aWN0aW1zX2luanVyZWQgLWhhZF9zdXJ2aXZvciwgZGF0YSA9IHRyYWluRGF0YSwgbWV0aG9kID0gImdsbSIsIGZhbWlseSA9ICJiaW5vbWlhbCIsIHRyQ29udHJvbCA9IHRyYWluX2NvbnRyb2wsIG1ldHJpYyA9ICJST0MiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBMb2dpc3RpYyBSZWdyZXNzaW9uIHdpdGggU3RlcCBXaXNlIGFuZCBrQ1YNCnN0ZXBMb2dQcmVkIDwtIHByZWRpY3Qoc3RlcExvZ01vZGVsQ1YsIG5ld2RhdGEgPSB0ZXN0RGF0YSwgdHlwZSA9ICJwcm9iIikNCnJvY09iIDwtIHJvYyh0ZXN0RGF0YSRoYWRfc3Vydml2b3IsIHN0ZXBMb2dQcmVkJFllcykNCnBsb3Qocm9jT2IsIHByaW50LmF1YyA9IFRSVUUsDQogICAgICAgICBjb2wgPSAiYmx1ZSIsDQogICAgICAgICBsd2QgPSAzLA0KICAgICAgICAgbGVnYWN5LmF4ZXMgPSBUUlVFLA0KICAgICAgICAgbWFpbiA9ICJST0MgQ3VydmUgZm9yIFN1cnZpdmFsIFByZWRpY3Rpb24iKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gInJlZCIpDQphdWMocm9jT2IpDQpgYGANCg0KDQoNCg==